#include "light/ws2812b.h"
#include <stddef.h>
#include <stdlib.h>

void _ws2812b_rgb2mosi(uint32_t rgb, uint8_t* mosi)
{
	int i = 0;     // 循环变量
	uint8_t r = 0; // 存放 R 分量
	uint8_t g = 0; // 存放 G 分量
	uint8_t b = 0; // 存放 B 分量
	uint8_t tmp_color = 0;
	uint32_t tmp_data = 0;
	r = (rgb & 0xff0000) >> 16;
	g = (rgb & 0x00ff00) >> 8;
	b = (rgb & 0x0000ff);

	/* 按照 GRB 的顺序发，且先发高位 */

	/* 构造 spi mosi 输出数据数组，spi 也是 MSB 先发送 */

	/* 当前 bit 是 0, 则转化为 0b100, 0x4 */
	/* 当前 bit 是 1, 则转化为 0b110, 0x6 */

	/* G */
	tmp_color = g;
	tmp_data = 0;
	for (i = 0; i < 8; i++) {
		if ((tmp_color >> i) & 0x1) {
			tmp_data |= 0x6 << (3 * i);
		} else {
			tmp_data |= 0x4 << (3 * i);
		}
	}
	mosi[0] = (tmp_data & 0xff0000) >> 16;
	mosi[1] = (tmp_data & 0x00ff00) >> 8;
	mosi[2] = (tmp_data & 0x0000ff);

	/* R */
	tmp_color = r;
	tmp_data = 0;
	for (i = 0; i < 8; i++) {
		if ((tmp_color >> i) & 0x1) {
			tmp_data |= 0x6 << (3 * i);
		} else {
			tmp_data |= 0x4 << (3 * i);
		}
	}
	mosi[3] = (tmp_data & 0xff0000) >> 16;
	mosi[4] = (tmp_data & 0x00ff00) >> 8;
	mosi[5] = (tmp_data & 0x0000ff);

	/* B */
	tmp_color = b;
	tmp_data = 0;
	for (i = 0; i < 8; i++) {
		if ((tmp_color >> i) & 0x1) {
			tmp_data |= 0x6 << (3 * i);
		} else {
			tmp_data |= 0x4 << (3 * i);
		}
	}
	mosi[6] = (tmp_data & 0xff0000) >> 16;
	mosi[7] = (tmp_data & 0x00ff00) >> 8;
	mosi[8] = (tmp_data & 0x0000ff);
}

/**
 * @brief 逐一发送 WS2812B 数据
 * @param color WS2812B 灯珠颜色数据, 使用 uint32_t 数据存储每个灯珠的颜色值，颜色值仅低24bit有效，颜色格式为 RGB888
 * @param num WS2812B 灯珠个数
 */
int ws2812b_write(ws2812b_t* led, uint32_t* color, uint32_t num)
{
	int i = 0;
	int size = 0;
	uint8_t* buffer = NULL;

	/* 检查参数有效性 */
	if (NULL == color) {
		return -1;
	}

	if (num <= 0) {
		return -1;
	}

	/* 一个 WS2812B 需要 24bit 表示其颜色，而 esp32c3 使用 3bit SPI bit 模拟一个 WS2812B 的 bit */
	/* 也就是一共需要 24x3 = 72 SPI bit 表示一个 WS2812B 的颜色值。 72 spi bit 就是 9 SPI Byte */
	size = num * 9;

	/* 申请内存用于存放转化后的 SPI 数据 */
	buffer = malloc(size);

	/* 将 RGB888 表示的彩灯颜色数组转化为 SPI 数据 */
	for (i = 0; i < num; i++) {
		_ws2812b_rgb2mosi(color[i], &buffer[9 * i]);
	}

	/* 调用芯片硬件 SPI 接口发送数据 */
	led->ops.spi_write(buffer, size);

	/* 释放内存 */
	free(buffer);

	return 0;
}